package com.crawler.system.controller;

import com.crawler.system.dto.CommonResult;
import com.crawler.system.dto.PageResult;
import com.crawler.system.entity.CrawlerResult;
import com.crawler.system.entity.CrawlerTask;
import com.crawler.system.dto.CrawlerTaskDTO;
import com.crawler.system.service.CrawlerService;
import com.crawler.system.util.ExportType;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.core.io.Resource;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletResponse;
import javax.validation.Valid;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 爬虫控制器
 * 提供爬虫任务的增删改查，以及任务执行控制和结果查询导出等接口
 */
@Slf4j
@RestController
@RequestMapping("/crawler")
@RequiredArgsConstructor
@Tag(name = "爬虫服务接口", description = "爬虫任务管理、执行和结果处理相关接口")
public class CrawlerController {

    private final CrawlerService crawlerService;

    @PostMapping("/tasks")
    @Operation(summary = "创建爬虫任务", description = "创建一个新的爬虫任务")
    @PreAuthorize("hasAuthority('crawler:task:create')")
    public CommonResult<Long> createTask(@Valid @RequestBody CrawlerTaskDTO taskDTO) {
        log.info("创建爬虫任务: {}", taskDTO);
        // 转换为实体对象
        CrawlerTask task = new CrawlerTask();
        BeanUtils.copyProperties(taskDTO, task);
        Long taskId = crawlerService.createTask(task);
        return CommonResult.success(taskId, "创建任务成功");
    }

    @PutMapping("/tasks/{taskId}")
    @Operation(summary = "更新爬虫任务", description = "更新指定ID的爬虫任务")
    @PreAuthorize("hasAuthority('crawler:task:update')")
    public CommonResult<Boolean> updateTask(
            @Parameter(description = "任务ID", required = true) @PathVariable Long taskId, 
            @Valid @RequestBody CrawlerTaskDTO taskDTO) {
        log.info("更新爬虫任务: {}, {}", taskId, taskDTO);
        taskDTO.setId(taskId);
        // 转换为实体对象
        CrawlerTask task = new CrawlerTask();
        BeanUtils.copyProperties(taskDTO, task);
        boolean result = crawlerService.updateTask(task);
        return CommonResult.success(result, "更新任务成功");
    }

    @DeleteMapping("/tasks/{taskId}")
    @Operation(summary = "删除爬虫任务", description = "删除指定ID的爬虫任务")
    @PreAuthorize("hasAuthority('crawler:task:delete')")
    public CommonResult<Boolean> deleteTask(
            @Parameter(description = "任务ID", required = true) @PathVariable Long taskId) {
        log.info("删除爬虫任务: {}", taskId);
        boolean result = crawlerService.deleteTask(taskId);
        return CommonResult.success(result, "删除任务成功");
    }

    @GetMapping("/tasks/{taskId}")
    @Operation(summary = "获取爬虫任务详情", description = "获取指定ID的爬虫任务详情")
    @PreAuthorize("hasAuthority('crawler:task:view')")
    public CommonResult<CrawlerTaskDTO> getTask(
            @Parameter(description = "任务ID", required = true) @PathVariable Long taskId) {
        log.info("获取爬虫任务详情: {}", taskId);
        CrawlerTaskDTO taskDTO = crawlerService.getTask(taskId);
        return CommonResult.success(taskDTO);
    }

    @GetMapping("/tasks")
    @Operation(summary = "获取爬虫任务列表", description = "分页获取爬虫任务列表，支持多种查询条件")
    @PreAuthorize("hasAuthority('crawler:task:list')")
    public CommonResult<PageResult<CrawlerTaskDTO>> listTasks(
            @Parameter(description = "页码，从1开始") @RequestParam(defaultValue = "1") Integer pageNum,
            @Parameter(description = "每页条数") @RequestParam(defaultValue = "10") Integer pageSize,
            @Parameter(description = "任务名称，模糊匹配") @RequestParam(required = false) String name,
            @Parameter(description = "任务状态") @RequestParam(required = false) String status,
            @Parameter(description = "任务类型") @RequestParam(required = false) String type,
            @Parameter(description = "创建人ID") @RequestParam(required = false) Long createdBy,
            @Parameter(description = "开始时间，格式：yyyy-MM-dd HH:mm:ss") @RequestParam(required = false) String startTime,
            @Parameter(description = "结束时间，格式：yyyy-MM-dd HH:mm:ss") @RequestParam(required = false) String endTime) {
        
        log.info("获取爬虫任务列表，参数 pageNum={}, pageSize={}, name={}, status={}, type={}, createdBy={}, startTime={}, endTime={}",
                pageNum, pageSize, name, status, type, createdBy, startTime, endTime);
                
        Map<String, Object> params = new HashMap<>();
        params.put("pageNum", pageNum);
        params.put("pageSize", pageSize);
        params.put("name", name);
        params.put("status", status);
        params.put("type", type);
        params.put("createdBy", createdBy);
        params.put("startTime", startTime);
        params.put("endTime", endTime);
        
        List<CrawlerTaskDTO> taskList = convertToDTOList(crawlerService.listTasks(params));
        PageResult<CrawlerTaskDTO> pageResult = new PageResult<>(pageNum, pageSize, (long)taskList.size(), taskList);
        return CommonResult.success(pageResult);
    }

    @PostMapping("/tasks/{taskId}/start")
    @Operation(summary = "开始爬虫任务", description = "开始执行指定ID的爬虫任务")
    @PreAuthorize("hasAuthority('crawler:task:execute')")
    public CommonResult<List<Long>> startTask(
            @Parameter(description = "任务ID", required = true) @PathVariable Long taskId) {
        log.info("开始爬虫任务: {}", taskId);
        List<Long> resultIds = crawlerService.startTask(taskId);
        return CommonResult.success(resultIds, "开始任务成功");
    }

    @PostMapping("/tasks/{taskId}/stop")
    @Operation(summary = "停止爬虫任务", description = "停止执行指定ID的爬虫任务")
    @PreAuthorize("hasAuthority('crawler:task:execute')")
    public CommonResult<Boolean> stopTask(
            @Parameter(description = "任务ID", required = true) @PathVariable Long taskId) {
        log.info("停止爬虫任务: {}", taskId);
        boolean result = crawlerService.stopTask(taskId);
        return CommonResult.success(result, "停止任务成功");
    }

    @PostMapping("/tasks/{taskId}/pause")
    @Operation(summary = "暂停爬虫任务", description = "暂停执行指定ID的爬虫任务")
    @PreAuthorize("hasAuthority('crawler:task:execute')")
    public CommonResult<Boolean> pauseTask(
            @Parameter(description = "任务ID", required = true) @PathVariable Long taskId) {
        log.info("暂停爬虫任务: {}", taskId);
        boolean result = crawlerService.pauseTask(taskId);
        return CommonResult.success(result, "暂停任务成功");
    }

    @PostMapping("/tasks/{taskId}/resume")
    @Operation(summary = "恢复爬虫任务", description = "恢复执行指定ID的爬虫任务")
    @PreAuthorize("hasAuthority('crawler:task:execute')")
    public CommonResult<Boolean> resumeTask(
            @Parameter(description = "任务ID", required = true) @PathVariable Long taskId) {
        log.info("恢复爬虫任务: {}", taskId);
        boolean result = crawlerService.resumeTask(taskId);
        return CommonResult.success(result, "恢复任务成功");
    }

    @GetMapping("/tasks/{taskId}/progress")
    @Operation(summary = "获取爬虫任务进度", description = "获取指定ID的爬虫任务进度")
    @PreAuthorize("hasAuthority('crawler:task:view')")
    public CommonResult<Integer> getTaskProgress(
            @Parameter(description = "任务ID", required = true) @PathVariable Long taskId) {
        log.info("获取爬虫任务进度: {}", taskId);
        Integer progress = crawlerService.getTaskProgress(taskId);
        return CommonResult.success(progress);
    }

    @GetMapping("/tasks/{taskId}/status")
    @Operation(summary = "获取爬虫任务状态", description = "获取指定ID的爬虫任务状态")
    @PreAuthorize("hasAuthority('crawler:task:view')")
    public CommonResult<String> getTaskStatus(
            @Parameter(description = "任务ID", required = true) @PathVariable Long taskId) {
        log.info("获取爬虫任务状态: {}", taskId);
        String status = crawlerService.getTaskStatus(taskId);
        return CommonResult.success(status);
    }

    @GetMapping("/tasks/{taskId}/statistics")
    @Operation(summary = "获取爬虫任务统计信息", description = "获取指定ID的爬虫任务统计信息")
    @PreAuthorize("hasAuthority('crawler:task:view')")
    public CommonResult<Map<String, Object>> getTaskStatistics(
            @Parameter(description = "任务ID", required = true) @PathVariable Long taskId) {
        log.info("获取爬虫任务统计信息: {}", taskId);
        Map<String, Object> statistics = crawlerService.getTaskStatistics(taskId);
        return CommonResult.success(statistics);
    }

    @GetMapping("/tasks/{taskId}/results")
    @Operation(summary = "获取爬虫任务结果列表", description = "分页获取指定任务ID的爬虫结果列表")
    @PreAuthorize("hasAuthority('crawler:result:view')")
    public CommonResult<PageResult<CrawlerResult>> listTaskResults(
            @Parameter(description = "任务ID", required = true) @PathVariable Long taskId,
            @Parameter(description = "页码，从1开始") @RequestParam(defaultValue = "1") Integer pageNum,
            @Parameter(description = "每页条数") @RequestParam(defaultValue = "10") Integer pageSize,
            @Parameter(description = "关键词搜索") @RequestParam(required = false) String keyword,
            @Parameter(description = "排序字段") @RequestParam(required = false, defaultValue = "id") String sortField,
            @Parameter(description = "排序方式：asc/desc") @RequestParam(required = false, defaultValue = "desc") String sortOrder) {
        
        log.info("获取爬虫任务结果列表，参数 taskId={}, pageNum={}, pageSize={}, keyword={}, sortField={}, sortOrder={}",
                taskId, pageNum, pageSize, keyword, sortField, sortOrder);
                
        Map<String, Object> params = new HashMap<>();
        params.put("pageNum", pageNum);
        params.put("pageSize", pageSize);
        params.put("keyword", keyword);
        params.put("sortField", sortField);
        params.put("sortOrder", sortOrder);
        
        List<CrawlerResult> resultList = crawlerService.listTaskResults(taskId, params);
        PageResult<CrawlerResult> pageResult = new PageResult<>(pageNum, pageSize, (long)resultList.size(), resultList);
        return CommonResult.success(pageResult);
    }

    @GetMapping("/results/{resultId}")
    @Operation(summary = "获取爬虫结果详情", description = "获取指定ID的爬虫结果详情")
    @PreAuthorize("hasAuthority('crawler:result:view')")
    public CommonResult<?> getTaskResult(
            @Parameter(description = "结果ID", required = true) @PathVariable Long resultId) {
        log.info("获取爬虫结果详情: {}", resultId);
        Object result = crawlerService.getTaskResult(resultId);
        return CommonResult.success(result);
    }

    @PostMapping("/tasks/{taskId}/export")
    @Operation(summary = "导出爬虫任务结果", description = "导出指定任务ID的爬虫结果，支持导出全部或部分结果")
    @PreAuthorize("hasAuthority('crawler:result:export')")
    public ResponseEntity<Resource> exportTaskResults(
            @Parameter(description = "任务ID", required = true) @PathVariable Long taskId,
            @Parameter(description = "导出类型：CSV、EXCEL、JSON", required = true) @RequestParam String exportType,
            @Parameter(description = "导出的结果ID列表，为空则导出全部") @RequestParam(required = false) List<Long> resultIds,
            HttpServletResponse response) throws IOException {
        
        log.info("导出爬虫任务结果，参数 taskId={}, exportType={}, resultIds={}", taskId, exportType, resultIds);
        
        String filePath = crawlerService.exportTaskResults(taskId, exportType, resultIds);
        
        // 创建资源
        Resource resource = new org.springframework.core.io.FileSystemResource(filePath);
        
        // 设置响应头
        String filename = "crawler_results_" + taskId + "_" + System.currentTimeMillis() + "." + exportType.toLowerCase();
        
        return ResponseEntity.ok()
                .header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\"" + filename + "\"")
                .contentType(MediaType.APPLICATION_OCTET_STREAM)
                .body(resource);
    }
    
    /**
     * 将爬虫任务列表转换为DTO列表
     * 
     * @param taskList 爬虫任务列表
     * @return 爬虫任务DTO列表
     */
    private List<CrawlerTaskDTO> convertToDTOList(List<CrawlerTask> taskList) {
        List<CrawlerTaskDTO> dtoList = new ArrayList<>();
        if (taskList != null && !taskList.isEmpty()) {
            for (CrawlerTask task : taskList) {
                CrawlerTaskDTO dto = new CrawlerTaskDTO();
                BeanUtils.copyProperties(task, dto);
                dtoList.add(dto);
            }
        }
        return dtoList;
    }
} 
